#include <pthread.h>
#include <unistd.h>
#include <iostream>
#include <sys/syscall.h>
#include <cstring>
#include <sys/timerfd.h>

#include "CurrentThread.h"
#include "Mutex.h"
#include "Condition.h"
#include "EventLoop.h"
#include "Channel.h"
#include "Acceptor.h"
#include "InetAddress.h"
#include "callbacks.h"
#include "TcpConnection.h"
#include "TcpServer.h"
#include "Buffer.h"
#include "Thread.h"
#include "EventLoopThread.h"

using namespace std;
using namespace std::placeholders;

Mutex mutex;
Condition cond(mutex);
EventLoop g_loop;

TcpConnectionPtr conn;
InetAddress serverAddr(2022);

void onConnect(TcpConnectionPtr conn) {
    if (conn->isConnected()) {
        std::cout << "TcpConnection connect" << endl;
    } else {
        std::cout << "TcpConnection disconnect" << endl;
    }
}

void onMessage(TcpConnectionPtr conn, Buffer& buffer) {
    buffer.printContent();
    conn->send("welcome!\n");
}

void onWriteComplete(TcpConnectionPtr conn) {
    cout << "writeComplete" << endl;
    // conn->forceClose();
    // cout << "after forceClose" << endl;
}

void test() {
    TcpServer server(&g_loop, serverAddr);
    server.setThreadNum(2);
    server.setConnectionCallback(onConnect);
    server.setMessageCallback(onMessage);
    server.setWriteCompleteCallback(onWriteComplete);
    server.start();
    g_loop.loop();
}

int timerfd;

void onTimer(const char* str) {
    uint64_t data;
    if (read(timerfd, &data, sizeof data) < 0) {
        cout << "onTimer error";
        abort();
    }
    printf("%s\n", str);
    fflush(stdout);

}

void testWithBug() {
    TimeStamp when = addTime(TimeStamp::now(), 6);
    g_loop.runAt(when, std::bind(onTimer, "run at test"));
    g_loop.loop();
}

void testTimerfd() {
    timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
    Channel channel(&g_loop, timerfd);
    channel.setReadCallback(std::bind(onTimer, "onTimer is excuting"));
    channel.enableReading();

    itimerspec old_value;
    itimerspec new_value;
    bzero(&old_value, sizeof old_value);
    bzero(&new_value, sizeof new_value);
    new_value.it_value.tv_sec = 5;
    new_value.it_interval.tv_sec = 3;
    timerfd_settime(timerfd, 0, &new_value, &old_value);
    g_loop.loop();
}

int main() {
    testWithBug();
    
    return 0;
}